/******************************************************************************
** 公司名称：天津柯迪斯科技有限公司
** 版权信息：
** 文件名称： App_Protocol_BF_BAT.c
** 模块名称： 八方电池通信模块
** 版 本 号： V1.0
** 作    者： 蒲磊
**
** 修改记录： 版本     修改人      时间         修改内容
******************************************************************************/

/******************************************************************************
* 头文件
******************************************************************************/
#include <string.h>
#include "Config.h"
#include "App_Protocol_BF_BAT.h"
#include "App_MainTask.h"
#include "App_Parameter.h"
/******************************************************************************
* 本文件宏定义 ('#define')
******************************************************************************/

/******************************************************************************
* 本文件类型定义 ('typedef')
******************************************************************************/

/******************************************************************************
* 本文件静态函数声明 ('static')
******************************************************************************/


/******************************************************************************
* 全局变量定义
******************************************************************************/
stBATTERY_INFO  gtBattery;
uint8_t gucCmd_Read_En[16] = {   READ_BAT_TEMP,                       /*是否读取电池组温度*/
                                 READ_BAT_VOLT,                       /*是否读取电池组电压*/
                                 READ_BAT_CURRENT,                    /*是否读取电池组电流*/
                                 READ_BAT_SOC,                        /*是否读取相对容量百分比*/
                                 READ_BAT_SOC_ABS,                    /*是否读取绝对容量百分比*/
                                 READ_BAT_CAP,                        /*是否读取剩余容量*/
                                 READ_BAT_CAP_FULL,                   /*是否读取满电容量*/
                                 READ_BAT_CYCLES,                     /*是否读取循环次数*/
                                 READ_BAT_CELL1_7,                    /*是否读取1-7电芯电压*/
                                 READ_BAT_CELL8_14,                   /*是否读取8-14电芯电压*/
                                 READ_BAT_UNCHARGING_TIME,            /*是否读取当前充电间隔时间*/
                                 READ_BAT_UNCHARGING_TIME_MAX,        /*是否读取最大充电间隔时间*/
                                 READ_BAT_TYPE,                       /*是否读取电池组型号*/
                                 READ_BAT_SW,                         /*是否读取电池软件版本号*/
                                 READ_BAT_SN,                         /*是否读取电池SN号*/
                                 READ_BAT_HW,                         /*是否读取电池硬件版本号*/

                             };
uint8_t gucCmd[16] = {0x08,0x09,0x0A,0x0D,0x0E,0x0F,0x10,0x17,0x24,0x25,0x47,0x48,0x50,0x51,0x52,0x53};
uint32_t gulErrCnt = 0;
uint8_t gucIsReadSoc = 0;
/*****************************************************************************
* 函数实现 - global ('extern') and local ('static')
******************************************************************************/




/******************************************************************************
** 功  能：获取电池温度
** 参  数：无
** 返回值：电池温度，精度0.1℃
** 备  注：
******************************************************************************/
int16_t sBF_BAT_Get_Temp(void)
{
    return gtBattery.Temp;
}

/******************************************************************************
** 功  能：获取当前电压值
** 参  数：无
** 返回值：实际电压值，单位mV
** 备  注：
******************************************************************************/
uint16_t usBF_BAT_Get_Volt(void)
{
    return gtBattery.Volt;
}

/******************************************************************************
** 功  能：获取当前电流值
** 参  数：无
** 返回值：实际电流值，单位mA
** 备  注：
******************************************************************************/
int16_t usBF_BAT_Get_Current(void)
{
    return gtBattery.Current;
}

/******************************************************************************
** 功  能：获取电池容量
** 参  数：无
** 返回值：电池容量，0-100%
** 备  注：
******************************************************************************/
int8_t cBF_BAT_Get_Soc(void)
{
    if(gucIsReadSoc == 0)
    {
        return -1;  /*没有读取到SOC值的时候，返回-1*/
    }
    else
    {
        return gtBattery.Soc;
    }
}

/******************************************************************************
** 功  能：获取绝对电池容量
** 参  数：无
** 返回值：电池容量，0-100%
** 备  注：
******************************************************************************/
uint8_t ucBF_BAT_Get_Soc_ABS(void)
{
    return gtBattery.Soc_Abs;
}

/******************************************************************************
** 功  能：获取电池剩余容量
** 参  数：无
** 返回值：剩余容量，单位mAh
** 备  注：
******************************************************************************/
uint16_t usBF_BAT_Get_Cap(void)
{
    return gtBattery.Cap;
}

/******************************************************************************
** 功  能：获取电池满电容量
** 参  数：无
** 返回值：满电容量，单位mAh
** 备  注：
******************************************************************************/
uint16_t usBF_BAT_Get_CapFull(void)
{
    return gtBattery.Cap_Full;
}

/******************************************************************************
** 功  能：获取电池组循环次数
** 参  数：无
** 返回值：循环次数
** 备  注：
******************************************************************************/
uint16_t usBF_BAT_Get_Cycles(void)
{
    return gtBattery.Cycles;
}

/******************************************************************************
** 功  能：获取电池组最近的充电时间间隔
** 参  数：无
** 返回值：充电时间间隔，单位：h
** 备  注：
******************************************************************************/
uint16_t usBF_BAT_Get_UnChargingTime(void)
{
    return gtBattery.NoChargingTime;
}

/******************************************************************************
** 功  能：获取电池组最大的充电时间间隔
** 参  数：无
** 返回值：充电时间间隔，单位：h
** 备  注：
******************************************************************************/
uint16_t usBF_BAT_Get_UnChargingTime_Max(void)
{
    return gtBattery.NoChargingTime_Max;
}

/******************************************************************************
** 功  能：获取电池组电芯总数
** 参  数：无
** 返回值：电芯总数量
** 备  注：
******************************************************************************/
uint8_t usBF_BAT_Get_CellNum(void)
{
    return gtBattery.CellNum_1 + gtBattery.CellNum_2;
}

/******************************************************************************
** 功  能：获取某一个电芯单体电压
** 参  数：Cell-要获取电压的电芯编号，1-14
** 返回值：电芯电压，单位mV
** 备  注：
******************************************************************************/
uint16_t usBF_BAT_Get_Cell_Volt(uint8_t Cell)
{
    return gtBattery.CellVolt[Cell];
}

/******************************************************************************
** 功  能：获取电池通信状态
** 参  数：无
** 返回值：电池通信错误状态，0-正常，1-通信错误
** 备  注：
******************************************************************************/
uint8_t ucBF_BAT_Get_Communication_Err(void)
{
    return gtBattery.Error;
}

/******************************************************************************
** 功  能：获取电池硬件版本号
** 参  数：pHW-存储电池硬件版本号的指针，Len-字符串最大长度
** 返回值：实际拷贝的字符串长度
** 备  注：
******************************************************************************/
uint8_t vBF_BAT_Get_HardwareVersion(char *pHW,uint8_t len)
{
    uint8_t n = 0;
    while(n < len)
    {
        if(gtBattery.HardVer[n] > 0)
        {
            *(pHW + n) = gtBattery.HardVer[n];
            n++;
        }
        else
        {
            break;
        }
    }
    return n;
}

/******************************************************************************
** 功  能：获取电池软件版本号
** 参  数：pHW-存储电池软件版本号的指针，Len-字符串最大长度
** 返回值：无
** 备  注：
******************************************************************************/
uint8_t vBF_BAT_Get_SoftwareVersion(char *pHW,uint8_t len)
{
    uint8_t n = 0;
    while(n < len)
    {
        if(gtBattery.SoftVer[n] > 0)
        {
            *(pHW + n) = gtBattery.SoftVer[n];
            n++;
        }
        else
        {
            break;
        }
    }
    return n;
}

/******************************************************************************
** 功  能：八方电池协议，发送读取数据指令
** 参  数：Cmd-要读取的命令
** 返回值：无
** 备  注：
******************************************************************************/
static void vBF_BAT_Send_Cmd(uint8_t Cmd)
{
    uint8_t TxBuffer[9];
    uint16_t lusCheckSum = 0;

    TxBuffer[0] = 0x3A; /*0x3A是帧头，0x16是电池系统地址。固定的*/
    TxBuffer[1] = 0x16;
    TxBuffer[2] = Cmd;  /*命令字*/
    TxBuffer[3] = 0x01; /*数据长度，此处默认1即可*/
    TxBuffer[4] = 0x00; /*有效数据，填0即可*/
    lusCheckSum = TxBuffer[1] + TxBuffer[2] + TxBuffer[3] + TxBuffer[4];    /*16位和校验*/
    TxBuffer[5] = lusCheckSum & 0x00FF; /*校验和低字节*/
    TxBuffer[6] = (lusCheckSum >> 8) & 0x00FF;/*校验和高字节*/
    TxBuffer[7] = 0x0D;
    TxBuffer[8] = 0x0A; /*0x0D,0xA,为固定帧尾*/

    USART_MCU_Send_Frame(TxBuffer,9);   /*送串口发送*/

}




/******************************************************************************
** 功  能：解析八方串口电池协议数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Get_Data_BF_BAT(uint8_t *pRxBuffer,uint16_t Len)
{
    uint16_t Checksum = 0;
    uint8_t n;
    for(n = 0; n < pRxBuffer[3] + 3; n++)
    {
        Checksum += pRxBuffer[n + 1];	/*计算校验值*/
    }
    /*首字节是0x3A，并且校验正确，认为接收数据无误*/
    if((pRxBuffer[0] == 0x3A) && (pRxBuffer[Len - 4] == Checksum % 256) && (pRxBuffer[Len - 3] == Checksum / 256))
    {
        gulErrCnt = 0;          /*复位错误计数*/
        switch(pRxBuffer[2])
        {
        case 0x08:/*电池组内部温度*/
        {
            gtBattery.Temp = ((int16_t)pRxBuffer[5] << 8) | pRxBuffer[4] - 2731;
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_TEMP == 1)
            {
                gucCmd_Read_En[0] = 0;
            }
            break;
        }
        case 0x09:/*电池总电压*/
        {
            gtBattery.Volt = ((uint16_t)pRxBuffer[5] << 8) | pRxBuffer[4];
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_VOLT == 1)
            {
                gucCmd_Read_En[1] = 0;
            }
            break;
        }
        case 0x0A:/*实时电流*/
        {
            gtBattery.Current = (int16_t)(((uint16_t)pRxBuffer[5] << 8) | pRxBuffer[4]);
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_CURRENT == 1)
            {
                gucCmd_Read_En[2] = 0;
            }
            break;
        }
        case 0x0D:/*相对容量百分比*/
        {
            gtBattery.Soc = pRxBuffer[4];
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_SOC == 1)
            {
                gucCmd_Read_En[3] = 0;
            }
            gucIsReadSoc = 1;   /*标识已读取到SOC*/
            break;
        }
        case 0x0E:/*决定容量百分比*/
        {
            gtBattery.Soc_Abs = pRxBuffer[4];
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_SOC_ABS == 1)
            {
                gucCmd_Read_En[4] = 0;
            }
            break;
        }
        case 0x0F:/*剩余容量*/
        {
            gtBattery.Cap = ((uint16_t)pRxBuffer[5] << 8) | pRxBuffer[4];
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_CAP == 1)
            {
                gucCmd_Read_En[5] = 0;
            }
            break;
        }
        case 0x10:/*满电容量*/
        {
            gtBattery.Cap_Full = ((uint16_t)pRxBuffer[5] << 8) | pRxBuffer[4];
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_CAP_FULL == 1)
            {
                gucCmd_Read_En[6] = 0;
            }
            break;
        }
        case 0x17:/*循环次数*/
        {
            gtBattery.Cycles = ((uint16_t)pRxBuffer[5] << 8) | pRxBuffer[4];
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_CYCLES == 1)
            {
                gucCmd_Read_En[7] = 0;
            }
            break;
        }
        case 0x24:/*1-7节电芯电压值*/
        {
            gtBattery.CellNum_1 = pRxBuffer[3] / 2;
            for(n = 0; n < pRxBuffer[3] / 2; n++)
            {
                gtBattery.CellVolt[n] = ((uint16_t)pRxBuffer[5 + n * 2] << 8) | pRxBuffer[4 + n * 2];
            }
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_CELL1_7 == 1)
            {
                gucCmd_Read_En[8] = 0;
            }
            break;
        }
        case 0x25:/*8-14节电芯电压值*/
        {
            gtBattery.CellNum_2 = pRxBuffer[3] / 2;
            for(n = 0; n < pRxBuffer[3] / 2; n++)
            {
                gtBattery.CellVolt[7 + n] = ((uint16_t)pRxBuffer[5 + n * 2] << 8) | pRxBuffer[4 + n * 2];
            }
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_CELL8_14 == 1)
            {
                gucCmd_Read_En[9] = 0;
            }
            break;
        }
        case 0x47:/*当前充电时间间隔*/
        {
            gtBattery.NoChargingTime = ((uint16_t)pRxBuffer[5] << 8) | pRxBuffer[4];
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_UNCHARGING_TIME == 1)
            {
                gucCmd_Read_En[10] = 0;
            }
            break;
        }
        case 0x48:/*最大充电时间间隔*/
        {
            gtBattery.NoChargingTime_Max = ((uint16_t)pRxBuffer[5] << 8) | pRxBuffer[4];
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_UNCHARGING_TIME_MAX == 1)
            {
                gucCmd_Read_En[11] = 0;
            }
            break;
        }
        case 0x50:/*电池组型号*/
        {
            for(n = 0; n < pRxBuffer[3]; n++)
            {
                gtBattery.Type[n] = pRxBuffer[4 + n];
            }
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_TYPE == 1)
            {
                gucCmd_Read_En[12] = 0;
            }
            break;
        }
        case 0x51:/*电池软件版本号*/
        {
            for(n = 0; n < pRxBuffer[3]; n++)
            {
                gtBattery.SoftVer[n] = pRxBuffer[4 + n];
            }
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_SW == 1)
            {
                gucCmd_Read_En[13] = 0;
            }
            break;
        }
        case 0x52:/*电池序列号*/
        {
            for(n = 0; n < pRxBuffer[3]; n++)
            {
                gtBattery.SN[n] = pRxBuffer[4 + n];
            }
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_SN == 1)
            {
                gucCmd_Read_En[14] = 0;
            }
            break;
        }
        case 0x53:/*电池硬件版本号*/
        {
            for(n = 0; n < pRxBuffer[3]; n++)
            {
                gtBattery.HardVer[n] = pRxBuffer[4 + n];
            }
            /*接收到对应的数据，并且改命令只要求读一次，则把数组中的变量置0，后续轮询就不再读取该参数*/
            if(READ_BAT_HW == 1)
            {
                gucCmd_Read_En[15] = 0;
            }
            break;
        }
        }
    }

    return;
}

/******************************************************************************
** 功  能：发送八方电池协议数据
** 参  数：无
** 返回值：无
** 备  注：这个函数需要定时调用。调用周期可以根据需要持续读取的数据量的大小做调整。一般100ms
******************************************************************************/
void vPROTOCOL_Send_Data_BF_BAT(void)
{
    static uint8_t lucCmd_Index = 0;
    /*在数组中查找对应的命令是否要读取，非零，需要读取*/
    while(gucCmd_Read_En[lucCmd_Index] == 0)
    {
        lucCmd_Index++;
        if(lucCmd_Index > 15)
        {
            lucCmd_Index = 0;
        }
    }

    vBF_BAT_Send_Cmd(gucCmd[lucCmd_Index]); /*读取对应的命令，进行发送*/
    lucCmd_Index++;
    if(lucCmd_Index > 15)
    {
        lucCmd_Index = 0;   /*数组循环查找*/
    }

    /*5秒钟之内没有接收到电池数据，认为是通信异常，置为错误标志*/
    gulErrCnt++;
    if(gulErrCnt > 50)
    {
        gtBattery.Error = 1;
    }
    else
    {
        gtBattery.Error = 0;
    }
}




